package com.zwcl.glass.tools.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zwcl.common.core.utils.JsonUtils;
import com.zwcl.glass.tools.api.entity.UserReport;
import com.zwcl.glass.tools.dto.HasTestDto;
import com.zwcl.glass.tools.dto.TestRecordDto;
import com.zwcl.glass.tools.entity.*;
import com.zwcl.glass.tools.mapper.TestRecordMapper;
import com.zwcl.glass.tools.service.PaperConclusionService;
import com.zwcl.glass.tools.service.PaperService;
import com.zwcl.glass.tools.service.RuleHandlerService;
import com.zwcl.glass.tools.service.TestRecordService;
import com.zwcl.common.mybatis.service.impl.BaseServiceImpl;
import com.zwcl.glass.tools.vo.UserTestRecordVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xieyongping
 * @since 2021-01-07
 */
@Service
public class TestRecordServiceImpl extends BaseServiceImpl<TestRecordMapper, TestRecord> implements TestRecordService {

    @Autowired
    private PaperConclusionService paperConclusionService;

    @Autowired
    private RuleHandlerService ruleHandlerService;

    @Autowired
    private PaperService paperService;

    @Autowired
    private TestRecordMapper testRecordMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveTestRecord(TestRecord testRecord) throws Exception {
        return super.save(testRecord);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateTestRecord(TestRecord testRecord) throws Exception {
        return super.updateById(testRecord);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteTestRecord(Long id) throws Exception {
        return super.removeById(id);
    }

    /**
     * 获取用户的测试报告
     * TODO:特殊的，针对眼镜和眼睛的瞳距，还需要加一个相差的结论
     * @param paperCodes
     * @param userId
     * @return
     */
    @Override
    public UserReport getUserTestReport(List<String> paperCodes, Integer userId) {
        UserReport userReport=new UserReport();
        //根据试卷类型，查询所有的最新的测试记录，找寻结论和标签
        List<TestRecord> list= getUserLastTestRecords(paperCodes,userId);
        //最新的用户报告
        Map<String,String> testReports=new HashMap<>();
        //最新的用户画像
        Map<String,String> testTags=new HashMap<>();
        list.forEach(item->{
            if(StringUtils.isNotBlank(item.getAutoConclusion())){
                testReports.put(item.getPaperCode(),item.getAutoConclusion());
            }
            if(StringUtils.isNotBlank(item.getAutoTags())){
                testTags.put(item.getPaperCode(),item.getAutoTags());
            }
        });
        userReport.setTestReports(testReports);
        userReport.setTestTags(testTags);
        return userReport;
    }

    @Override
    public List<TestRecord> getUserLastTestRecords(List<String> paperCodes, Integer userId) {
        List<TestRecord> list= testRecordMapper.selectUserLastTestRecord(userId,paperCodes);
        return list;
    }

    @Override
    public List<TestRecord> getUserTestRecords(HasTestDto dto) {
        LambdaQueryWrapper<TestRecord> queryWrapper=new LambdaQueryWrapper<>();
        if(dto.getPaperId()!=null){
            queryWrapper.eq(TestRecord::getPaperId,dto.getPaperId());
        }
        if(dto.getPaperCode()!=null){
            queryWrapper.eq(TestRecord::getPaperCode,dto.getPaperCode());
        }
        if(dto.getUserId()!=null){
            queryWrapper.eq(TestRecord::getUserId,dto.getUserId());
        }
        if(dto.getPhone()!=null){
            queryWrapper.eq(TestRecord::getPhone,dto.getPhone());
        }
        queryWrapper.eq(TestRecord::getDelFlag,false);
        queryWrapper.orderByDesc(TestRecord::getCreateTime);
        if(dto.getGetAll()==null || dto.getGetAll()){
            return this.list(queryWrapper);
        }else {
            queryWrapper.last("limit 1");
            return Arrays.asList(this.getOne(queryWrapper));
        }
    }


    @Override
    public Integer getUserTestTimes(HasTestDto dto) {
        LambdaQueryWrapper<TestRecord> queryWrapper=new LambdaQueryWrapper<>();
        if(dto.getPaperId()!=null){
            queryWrapper.eq(TestRecord::getPaperId,dto.getPaperId());
        }
        if(dto.getPaperCode()!=null){
            queryWrapper.eq(TestRecord::getPaperCode,dto.getPaperCode());
        }
        if(dto.getUserId()!=null){
            queryWrapper.eq(TestRecord::getUserId,dto.getUserId());
        }
        if(dto.getPhone()!=null){
            queryWrapper.eq(TestRecord::getPhone,dto.getPhone());
        }
        queryWrapper.eq(TestRecord::getDelFlag,false);
        return this.count(queryWrapper);
    }

    @Override
    public Map<String, Integer> getUserTestTimes(List<String> paperCodes, Integer userId) {
        List<UserTestRecordVo> list = testRecordMapper.countUserTestNum(userId,paperCodes);
        return list.stream().collect(Collectors.toMap(x->x.getPaperCode(),x->x.getTestTime()));
    }

    /**
     * 获取试卷的测试记录
     * @param dto
     * @return
     */
    @Override
    public TestRecord getUserTestRecord(TestRecordDto dto) {
        QueryWrapper<TestRecord> queryWrapper=new QueryWrapper<>();
        queryWrapper.lambda().eq(TestRecord::getUserId,dto.getUserId()).eq(TestRecord::getPaperId,dto.getPaperId());
        return this.getOne(queryWrapper);
    }

    /**
     * 根据答案获取测试的结论
     * @param dto
     * @return
     */
    @Override
    public List<String> generateTestConclusion(TestRecordDto dto) {
        //获取试卷的结论规则
        List<PaperConclusion> paperConclusions= paperConclusionService.getPaperConclusionList(dto.getPaperId());
        List<ConclusionRule> ruleList=new ArrayList<>();
        if(paperConclusions!=null) {
            //将表中的json字符串转化成对象
            paperConclusions.forEach(item -> {
                ConclusionRule vo = new ConclusionRule();
                BeanUtils.copyProperties(item, vo);
                List<ResultRule> resultRules = JsonUtils.jsonToList(item.getRuleContent(), ResultRule.class);
                vo.setRuleContent(resultRules);
                ruleList.add(vo);
            });
        }
        //进一步处理折射率的结果
        List<AnswerResultHanlder> answerResultHanlders=handlerAnswerResult(dto.getResultList());
        //生成测试的结论，这个测试的结果，有选择题，有滑块的取值题
        List<String> conclusionList= ruleHandlerService.generateConclusion(answerResultHanlders,ruleList);
        return conclusionList;
    }

    /**
     * 根据答案获取测试的结论
     * @param dto
     * @return
     */
    @Override
    public Map<String,List<String>> generateTestConclusionEx(TestRecordDto dto) {
        //获取试卷的结论规则
        List<PaperConclusion> paperConclusions=new ArrayList<>();
        if(null!=dto.getPaperCode()) {
            paperConclusions = paperConclusionService.getPaperConclusionListByCode(dto.getPaperCode());
            if(null==paperConclusions && null!=dto.getPaperId()){
                paperConclusions = paperConclusionService.getPaperConclusionList(dto.getPaperId());
            }
        }
        List<ConclusionRuleEx> ruleList=new ArrayList<>();
        if(paperConclusions!=null) {
            //将表中的json字符串转化成对象
            paperConclusions.forEach(item -> {
                ConclusionRuleEx vo = new ConclusionRuleEx();
                BeanUtils.copyProperties(item, vo);
                ResultRuleEx resultRules = JsonUtils.jsonToPojo(item.getRuleContent(), ResultRuleEx.class);
                vo.setRuleContent(resultRules);
                ruleList.add(vo);
            });
        }
        //进一步处理折射率的结果
        List<AnswerResultHanlder> answerResultHanlders=handlerAnswerResult(dto.getResultList());
        //生成测试的结论，这个测试的结果，有选择题，有滑块的取值题
        Map<String,List<String>> conclusionAndTagMap= ruleHandlerService.generateConclusionEx(answerResultHanlders,ruleList);
        return conclusionAndTagMap;
    }

    @Override
    public List<AnswerResultHanlder> handlerAnswerResult(List<AnswerResult> answerResults) {
        List<AnswerResultHanlder> answerResultHanlders=new ArrayList<>();
        for (AnswerResult item : answerResults) {
            switch (item.getProblemType()) {
                case 11:                                    //单选题
                case 21:                                    //滑块设置的题目，变为单选题
                    AnswerResultHanlder newResult1 = hanlderOptionResult(item);
                    answerResultHanlders.add(newResult1);
                    //语句
                    break;
                case 12 :
                    AnswerResultHanlder newResult2 = hanlderOptionResult(item);
                    answerResultHanlders.add(newResult2);
                    //语句
                    break;
//                case 21:
//                    AnswerResultHanlder newResult3 = hanlderSliderResult(item);
//                    answerResultHanlders.add(newResult3);
//                    //语句
//                    break;
                case 31:
                    AnswerResultHanlder newResult3 = hanlderShowResult(item);
                    answerResultHanlders.add(newResult3);
                default:
                    break;
            }
        }
        return answerResultHanlders;
    }

    private AnswerResultHanlder hanlderOptionResult(AnswerResult answerResult){
        AnswerResultHanlder newResult=new AnswerResultHanlder();
        newResult.setValueType(0);
        newResult.setProblemId(answerResult.getProblemId());
        newResult.setResult(answerResult.getResult());
        /**
         * 如果有值类型，统计值类型
         */
        if(null!=answerResult.getValue() && answerResult.getValue().length>0){
            Double total=0.0;
            for(int i=0;i<answerResult.getValue().length;i++){
                total+=Double.valueOf(answerResult.getValue()[i]);
            }
            newResult.setValueType(answerResult.getProblemType()==21? 1:2 ); //区分原滑块设置的题目，1为滑块设置，4题关联；2为统计个数
            newResult.setValue(total);
        }
        return newResult;
    }

    /**
     * 值直接显示
     * @param answerResult
     * @return
     */
    private AnswerResultHanlder hanlderShowResult(AnswerResult answerResult){
        AnswerResultHanlder newResult=new AnswerResultHanlder();
        newResult.setValueType(3);
        newResult.setProblemId(answerResult.getProblemId());
        newResult.setShowValue(answerResult.getShowValue());
        return newResult;
    }


    /**
     * 处理滑块折射率
     * @param answerResult
     * @return
     */
    private AnswerResultHanlder hanlderSliderResult(AnswerResult answerResult){
        AnswerResultHanlder newResult=new AnswerResultHanlder();
        String[] sliderResultArr=answerResult.getResult();
        //度数的映射
        Map<String,Float> degreeMap = new HashMap<>();
        for(String sliderResult : sliderResultArr){
            String[] keyValue=sliderResult.split(":");
            degreeMap.put(keyValue[0],Float.valueOf(keyValue[1]));
        }
        //计算度数，可能会有精度问题
        float leftDegree=degreeMap.get("leftShortSighted")+degreeMap.get("leftFlood")/2;
        float rightDegree=degreeMap.get("rightShortSighted")+degreeMap.get("rightFlood")/2;
        float degree=leftDegree>rightDegree?leftDegree:rightDegree;
        //计算折射率
        float refraction=degreeToRefraction(degree);
        newResult.setValueType(1);
        newResult.setProblemId(answerResult.getProblemId());
        newResult.setResult(new String[]{Float.toString(refraction)} );
        return newResult;
    }

    /**
     * 度数转换成折射率
     * @param degree
     * @return
     */
    private Float degreeToRefraction(float degree){
        float refraction=0.00F;
        if(degree>=-3.00F && degree<0.00F){
            refraction=1.56F;
        }else if(degree>=-5.00F && degree<-3.00F){
            refraction=1.61F;
        }else if(degree>=-7.00F && degree<-5.00F){
            refraction=1.67F;
        }else if(degree>=-9.00F && degree<-7.00F){
            refraction=1.74F;
        }else if(degree<-9.00F){
            refraction=1.74F;
        }else if(degree>=0.00F && degree<3.00F){
            refraction=1.56F;
        }else if(degree>=3.00F && degree<5.00F){
            refraction=1.61F;
        }else if(degree>=5.00F && degree<7.00F){
            refraction=1.67F;
        }else if(degree>=7.00F){
            refraction=1.74F;
        }
        return refraction;
    }
}
